package com.self.cloudmall.wms.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.self.cloudmall.common.dto.OrderDto;
import com.self.cloudmall.common.dto.SkuLockDto;
import com.self.cloudmall.common.dto.StockLockDto;
import com.self.cloudmall.common.dto.WareSkuLockDto;
import com.self.cloudmall.common.enumm.OrderStatusEnum;
import com.self.cloudmall.common.enumm.ResultErrorEum;
import com.self.cloudmall.common.enumm.StockLockEnum;
import com.self.cloudmall.common.utils.R;
import com.self.cloudmall.wms.client.OrderClient;
import com.self.cloudmall.wms.client.ProductClient;
import com.self.cloudmall.wms.entity.PurchaseDetailEntity;
import com.self.cloudmall.wms.entity.WareOrderLockEntity;
import com.self.cloudmall.wms.service.WareOrderLockService;
import com.self.cloudmall.wms.vo.PurchaseItemDoneVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.self.cloudmall.wms.utils.PageUtils;
import com.self.cloudmall.wms.utils.Query;

import com.self.cloudmall.wms.mapper.WareSkuMapper;
import com.self.cloudmall.wms.entity.WareSkuEntity;
import com.self.cloudmall.wms.service.WareSkuService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;


@Slf4j
@Service("wareSkuService")
public class WareSkuServiceImpl extends ServiceImpl<WareSkuMapper, WareSkuEntity> implements WareSkuService {

    @Autowired
    private ProductClient productClient;
    @Autowired
    private WareOrderLockService wareOrderLockService;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private OrderClient orderClient;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<WareSkuEntity> page = this.page(
                new Query<WareSkuEntity>().getPage(params),
                new QueryWrapper<WareSkuEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public PageUtils queryPageByCondition(Map<String, Object> params) {
        // skuId: this.dataForm.skuId,
        //          wareId
        QueryWrapper<WareSkuEntity> queryWrapper = new QueryWrapper<>();
        LambdaQueryWrapper<WareSkuEntity> lambda = queryWrapper.lambda();
        String skuId = (String) params.get("skuId");
        if (StringUtils.isNotEmpty(skuId)){
            lambda.eq(WareSkuEntity::getSkuId,skuId);
        }
        String wareId = (String) params.get("wareId");
        if (StringUtils.isNotEmpty(wareId)){
            lambda.eq(WareSkuEntity::getWareId,wareId);
        }
        IPage<WareSkuEntity> page = this.page(
                new Query<WareSkuEntity>().getPage(params),
                queryWrapper
        );

        return new PageUtils(page);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean addWareSku(PurchaseItemDoneVo item, PurchaseDetailEntity purchaseDetail) {
        List<WareSkuEntity> skuEntities = this.lambdaQuery().eq(WareSkuEntity::getSkuId, purchaseDetail.getSkuId())
                .eq(WareSkuEntity::getWareId, purchaseDetail.getWareId()).list();
        if (CollectionUtils.isEmpty(skuEntities)){
            WareSkuEntity wareSkuEntity = new WareSkuEntity();
            wareSkuEntity.setStockLocked(0);
            wareSkuEntity.setStock(item.getRealStock());
            wareSkuEntity.setReason(item.getReason());
            wareSkuEntity.setRealStock(item.getRealStock());
            wareSkuEntity.setWareId(purchaseDetail.getWareId());
            wareSkuEntity.setSkuId(purchaseDetail.getSkuId());
            //查询sku名称
            try {
                R info = productClient.info(purchaseDetail.getSkuId());
                if (!info.isSuccess()){
                    log.error("获取sku失败：{}", JSONObject.toJSONString(info));
                }
                Map<String,Object> map = (Map<String,Object>)info.get("skuInfo");
                if (map != null && !map.isEmpty()){
                    wareSkuEntity.setSkuName((String)map.get("skuName"));
                }
            } catch (Exception e) {
                log.error("获取sku名称异常：{}",e);
            }
            this.save(wareSkuEntity);
        }else {
            List<WareSkuEntity> collect = skuEntities.stream().map(x -> {
                WareSkuEntity wareSku = new WareSkuEntity();
                wareSku.setId(x.getId());
                int stock = 0;
                if (x.getStock() != null && item.getRealStock() != null) {
                    stock = item.getRealStock() + x.getStock();
                } else if (x.getStock() == null && item.getRealStock() != null) {
                    stock = item.getRealStock();
                } else {
                    stock = x.getStock();
                }
                wareSku.setStock(stock);
                wareSku.setReason(item.getReason());
                wareSku.setRealStock(item.getRealStock());
                return wareSku;
            }).collect(Collectors.toList());
            this.updateBatchById(collect);
        }

        return true;
    }

    @Override
    public Map<Long, Boolean> hasStock(List<Long> skuIds) {
        Map<Long, Boolean> map = Maps.newHashMap();
        for (Long skuId : skuIds){
            //现有库存=库存-锁库
           Long count= this.baseMapper.countStock(skuId);
           map.put(skuId,count==null?false : count > 0);
        }
        return map;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public R orderLockStock(WareSkuLockDto skuLockDto) {
        List<SkuLockDto> skuLocks = skuLockDto.getSkuLocks();
        List<WareOrderLockEntity> orderLockEntities = Lists.newArrayList();
        for (SkuLockDto lock : skuLocks){
            //查询skuID的库存存在的
            List<Long> list = this.baseMapper.queryExistStockBySkuId(lock.getSkuId());
            if (CollectionUtils.isEmpty(list)){
                return R.error(ResultErrorEum.ORDER_LOCK_STOCK_FAIL.getCode(),ResultErrorEum.ORDER_LOCK_STOCK_FAIL.getMessage());
            }
            boolean flag = false;
            for (Long wareId : list){
                Integer num = this.baseMapper.lockStockByWareIdAndSkuId(lock.getSkuId(),wareId,lock.getCount());
                //锁库成功
                if (num != null && num == 1){
                    flag = true;
                    WareOrderLockEntity orderLockEntity = new WareOrderLockEntity();
                    orderLockEntity.setLockState(StockLockEnum.LOCKED.getCode());
                    orderLockEntity.setSkuId(lock.getSkuId());
                    orderLockEntity.setOrderSn(skuLockDto.getOrderSn());
                    orderLockEntity.setSkuName(lock.getSkuTitle());
                    orderLockEntity.setSkuNum(lock.getCount());
                    orderLockEntity.setWareId(wareId);
                    orderLockEntities.add(orderLockEntity);
                    break;
                }
            }
            //锁库失败
            if (!flag){
                return R.error(ResultErrorEum.ORDER_LOCK_STOCK_FAIL.getCode(),ResultErrorEum.ORDER_LOCK_STOCK_FAIL.getMessage());
            }
        }
        //保存锁定记录，为了溯源
        wareOrderLockService.saveBatch(orderLockEntities);
        log.info("锁库存第一条记录：{}",JSONObject.toJSONString(orderLockEntities.get(0)));
        //将锁定的库存，发送给mq，是为了处理订单失败回滚，而库存锁定成功，需要发消息库存解算
        List<StockLockDto> stockLockDtos = orderLockEntities.stream().map(x -> {
            StockLockDto stockLockDto = new StockLockDto();
            BeanUtils.copyProperties(x,stockLockDto);
            return stockLockDto;
        }).collect(Collectors.toList());
        rabbitTemplate.convertAndSend("stock-event-exchange","stock.lock",stockLockDtos);
        return R.ok();
    }

    /**
     * 解锁步骤：
     * 查询库存锁定表，判断是否存在库存
     *   有:库存锁定成功，要解锁
     *      判断订单是否存在
     *        存在：说明订单下达成功，只有订单状态=“已取消”，才结算，其他无需解锁
     *   没有: 库存没有锁定成功就回滚了，不需要解锁
     * @param lockDtoList
     * @throws Exception
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void unLockStock(List<StockLockDto> lockDtoList) throws Exception {
        String orderSn = lockDtoList.get(0).getOrderSn();
        R statusR = orderClient.getOrderStatus(orderSn);
        boolean isRelease = false;
        if (statusR.isSuccess()){
            OrderDto status = JSONObject.parseObject(JSONObject.toJSONString(statusR.getData()), OrderDto.class);
            if (status == null || status.getStatus() == OrderStatusEnum.CANCLED.getCode().intValue()){
                isRelease = true;
            }
        }else{
            throw new Exception("解锁库存--获取订单状态失败");
        }
        for (StockLockDto lockDto : lockDtoList){
            WareOrderLockEntity wareOrderLock = wareOrderLockService.getById(lockDto.getId());
            if (wareOrderLock != null && wareOrderLock.getLockState() == StockLockEnum.LOCKED.getCode() && isRelease){
                this.baseMapper.unLockStock(lockDto.getSkuId(),lockDto.getWareId(),lockDto.getSkuNum());
                WareOrderLockEntity  lockEntity = new WareOrderLockEntity();
                lockEntity.setId(lockDto.getId());
                lockEntity.setLockState(StockLockEnum.UNLOCK.getCode());
                wareOrderLockService.updateById(lockEntity);
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void unLockStock(OrderDto orderDto) throws Exception {
        List<WareOrderLockEntity> list = wareOrderLockService.lambdaQuery().eq(WareOrderLockEntity::getOrderSn, orderDto.getOrderSn())
                .eq(WareOrderLockEntity::getLockState, StockLockEnum.LOCKED.getCode())
                .list();
        if (!CollectionUtils.isEmpty(list)){
            for (WareOrderLockEntity lockEntity : list){
                this.baseMapper.unLockStock(lockEntity.getSkuId(),lockEntity.getWareId(),lockEntity.getSkuNum());
                WareOrderLockEntity  lock = new WareOrderLockEntity();
                lock.setId(lockEntity.getId());
                lock.setLockState(StockLockEnum.UNLOCK.getCode());
                wareOrderLockService.updateById(lockEntity);
            }
        }
    }

}